﻿using System;
using Tools.Domain.Common.Repositories.Contracts;
using Tools.Domain.Specifications.Constraints;
using Web.App.Infrastructure.Context.Contracts;
using Web.App.Infrastructure.ObjectStore.Contracts;
using Web.App.Infrastructure.Security.Contracts;
using Webshop20.Application.Operations.Messages;
using Webshop20.Domain.Customers.Core;
using Webshop20.Domain.Customers.Factories.Contracts;
using Webshop20.Domain.Security.Authentication.Core;
using Webshop20.Domain.Security.Authentication.Factories.Contracts;
using Webshop20.Repositories.Contracts;
using Webshop20.Domain.Common.Exceptions;
using Tools.Domain.Common.ConstraintSets;

namespace Webshop20.Application.Operations.Services
{
    public interface IUpdateTransientNewRegistrationDataService: IService{}

    public class UpdateTransientNewRegistrationDataService : ServiceBase, IUpdateTransientNewRegistrationDataService
    {
        private readonly IAccountFactory accountFactory;
        private readonly ICustomerFactory customerFactory;
        private readonly IObjectStoreRepository objectStoreRepository; 
        private readonly IRepository<ControllQuestion> controllQuestionRepository;
        private readonly IHashService hashService;
        private readonly IConstraintSetFactory constraintSetFactory;


        public UpdateTransientNewRegistrationDataService(IAccountFactory accountFactory, ICustomerFactory customerFactory, IRepository<ControllQuestion> controllQuestionRepository, IHashService hashService, IConstraintSetFactory constraintSetFactory, IObjectStoreRepository objectStoreRepository)
        {
   
            this.constraintSetFactory = constraintSetFactory;
            this.objectStoreRepository = objectStoreRepository;
            this.hashService = hashService;
            this.accountFactory = accountFactory;
            this.customerFactory = customerFactory;
            this.controllQuestionRepository = controllQuestionRepository;
        }

        public override ISystemMessage Handle(ISystemMessage request)
        {
            var updateAccountRequest = request as UpdateTransientNewRegistrationDataRequest;
            
            UpdateTransientAccount(updateAccountRequest);

            if (DomainReportsFailure())
                return new UpdateTransientNewRegistrationDataResponse(domainMessage);
            
            UpdateTransientCustomer(updateAccountRequest);

            if (DomainReportsFailure())
                return new UpdateTransientNewRegistrationDataResponse(domainMessage);

            return new UpdateTransientNewRegistrationDataResponse(null);
        }

        private void UpdateTransientCustomer(UpdateTransientNewRegistrationDataRequest request)
        {
            Customer customerInProgress = (Customer)objectStoreRepository.Find(new Guid(request.CustomerInterimsKey)).Data ??
                            customerFactory.Create(request.EMail, request.FirstName, request.LastName);

            try
            {
                customerInProgress.SetCustomerData(
                request.FirstName,
                request.LastName,
                request.EMail,
                string.Empty,
                string.Empty,
                string.Empty,
                string.Empty,
                constraintSetFactory.Create<IConstraintSet<Customer>>(new AlwaysExceptForRegistration())
                );
            }
            catch (DomainException ex)
            {
                HandleDomainException(ex.DomainMessage);
            }


        }

        private void UpdateTransientAccount(UpdateTransientNewRegistrationDataRequest updateAccountRequest)
        {
            Account accountInProgress = (Account)objectStoreRepository.Find(new Guid(updateAccountRequest.AccountInterimsKey)).Data  ??
                                        accountFactory.Create();
            var controlQuestion = controllQuestionRepository.FindById(updateAccountRequest.ControllQuestion);

            try
            {

                var constraintSet = constraintSetFactory.Create<IConstraintSet<Account>>(new ExecuteAlways());

                accountInProgress.SetAccountData(
                 updateAccountRequest.EMail,
                 updateAccountRequest.Password,
                 updateAccountRequest.PasswordConfirm,
                 controlQuestion,
                 updateAccountRequest.ControllAnswer,
                 hashService,
                 constraintSet
                 ); 
            }
            catch(DomainException ex)
            {
                HandleDomainException(ex.DomainMessage);
            }

        }
    }
}